package httpContext

import (
	"context"
	"encoding/json"
	"gitee.com/jjawesomejj/awesomehttp/system/helper"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"sync"
)

type HttpContext struct {
	Response        http.ResponseWriter
	ResponseContent interface{}
	Request         *http.Request
	GetData         map[string]interface{}
	PostData        map[string]interface{}
	StartAt         float64
	RouteParams     map[string][]string
	Ctx             context.Context
	runTimeData     sync.Map
}

func (handler *HttpContext) SetHttpInfo(w http.ResponseWriter, r *http.Request) *HttpContext {
	handler.Request = r
	handler.Response = w
	return handler
}
func (handler *HttpContext) InitRequest() *HttpContext {
	if strings.Index(handler.Request.Header.Get("Content-Type"), "application/json") != -1 {
		handler.recvPostJsonData()
	} else {
		handler.recvPostData()
	}
	handler.recvGetData()
	return handler
}
func (handler *HttpContext) recvGetData() *HttpContext {
	if handler.GetData == nil {
		getData := make(map[string]interface{})
		queryString := strings.Split(handler.Request.RequestURI, "?")
		if len(queryString) < 2 {
			handler.GetData = map[string]interface{}{}
		} else {
			getData = handler.parseParamsStrings(queryString[1])
		}

		handler.GetData = getData
	}
	return handler
}
func (handler *HttpContext) parseParamsStrings(queryParamsString string) map[string]interface{} {
	res := make(map[string]interface{})
	queryParamsList := strings.Split(queryParamsString, "&")
	for _, value := range queryParamsList {
		paramsInfo := strings.Split(value, "=")
		if len(paramsInfo) == 2 {
			res[paramsInfo[0]] = paramsInfo[1]
		} else {
			res[paramsInfo[0]] = nil
		}
	}
	return res
}
func (handler *HttpContext) recvPostData() *HttpContext {
	if handler.PostData == nil {
		handler.PostData = make(map[string]interface{})
		a1, _ := ioutil.ReadAll(handler.Request.Body)
		parmas := handler.parseParamsStrings(string(a1))
		for key, value := range parmas {
			if value != nil {
				postValue, _ := url.QueryUnescape(value.(string))
				handler.PostData[key] = postValue
			}
		}
	}
	return handler
}
func (handler *HttpContext) recvPostJsonData() *HttpContext {
	if handler.PostData == nil {
		handler.PostData = make(map[string]interface{})
		decoder := json.NewDecoder(handler.Request.Body)
		var params map[string]interface{}
		decoder.Decode(&params)
		handler.PostData = params
	}
	return handler
}
func (handler *HttpContext) GetMany(keys ...string) map[string]interface{} {
	handler.recvGetData()
	res := make(map[string]interface{})
	if len(keys) != 0 {
		for _, key := range keys {
			res[key] = handler.GetData[key]
		}
	} else {
		res = handler.GetData
	}
	return res
}
func (handler *HttpContext) Get(key string, defaultValue ...interface{}) interface{} {

	if _, ok := handler.GetData[key]; ok {
		return handler.Request.URL.Query().Get(key)
	}
	if len(defaultValue) > 0 {
		return defaultValue[0]
	}
	return nil
}
func (handler *HttpContext) PostMany(keys ...string) map[string]interface{} {
	res := make(map[string]interface{})
	if len(keys) == 0 {
		res = handler.PostData
	} else {
		for _, key := range keys {
			res[key] = handler.PostData[key]
		}
	}
	return res
}
func (handler *HttpContext) PostOne(key string, defalut ...interface{}) interface{} {
	if value, ok := handler.PostData[key]; ok {
		return value
	}
	if len(defalut) > 0 {
		return defalut[0]
	} else {
		return nil
	}
}

func (handler *HttpContext) SetValue(key string, value interface{}) {
	handler.runTimeData.Store(key, value)
}

func (handler *HttpContext) GetValue(key string) interface{} {
	value, ok := handler.runTimeData.Load(key)
	if ok {
		return value
	}
	return nil
}

func (handler *HttpContext) SetCookie(name string, value string, path string, expire int, domain string) *HttpContext {
	if domain == "" {
		domain = handler.Request.Host
	}
	cookie := &http.Cookie{
		Name:   name,   //名字
		Value:  value,  //值
		Path:   path,   //路径
		Domain: domain, //域名
		MaxAge: expire, //存活时间
	}
	http.SetCookie(handler.Response, cookie)
	return handler
}
func GetHttpContext(w http.ResponseWriter, r *http.Request) *HttpContext {
	httpContext := HttpContext{
		Request:     r,
		Response:    w,
		StartAt:     helper.NowFloat(),
		RouteParams: make(map[string][]string),
		Ctx:         context.Background(),
	}
	//httpContext.InitRequest()
	return &httpContext
}
